#coding: utf-8
from django import forms
from django.forms.widgets import RadioSelect
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from models import *


def validate_cpf(cpf):
    w = [10, 9, 8, 7, 6, 5, 4, 3, 2]
    
    ocpf, verif = [int(a) for a in cpf[:-2]], [int(a) for a in cpf[-2:]]
    tmp = reduce(lambda a,b: a+b, map(lambda t: t[0]*t[1], zip(w, ocpf)))
    fdigit = tmp % 11
    fdigit = 0 if fdigit < 2 else 11 - fdigit
    
    w.insert(0, 11)
    ocpf.append(fdigit)
    tmp = reduce(lambda a,b: a+b, map(lambda t: t[0]*t[1], zip(w, ocpf)))
    sdigit = tmp % 11
    sdigit = 0 if sdigit < 2 else 11 - sdigit
    
    return [fdigit, sdigit] == verif


class RegistroUsuarioForm(forms.ModelForm):
    error_messages = {
        'invalid_cpf': "O CPF digitado não é um CPF válido.",
        'duplicate_username': "Já existe um cliente com esse CPF.",
        'duplicate_email': "Já existe um cliente com esse email.",
        'password_mismatch': "As senhas digitadas são diferentes.",
    }
    
    username = forms.RegexField(
        label='CPF', max_length=11, regex=r'^\d{11}$',
        help_text = 'Obrigatório. 11 caracteres. Apenas números.')
    email = forms.EmailField(label='Email', required=True, 
        help_text = 'Obrigatório.')
    first_name = forms.CharField(label=u'Primeiro nome', max_length=30, 
        required=True)
    last_name = forms.CharField(label=u'Segundo nome', max_length=30, 
        required=True)
    password1 = forms.CharField(label=u'Senha',
        widget=forms.PasswordInput)
    password2 = forms.CharField(label=u'Confirme a senha',
        widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'username', 'email',)

    def clean_username(self):
        cpf = self.cleaned_data['username']
        if not validate_cpf(cpf):
            raise forms.ValidationError(self.error_messages['invalid_cpf'])
        try:
            user = User.objects.get(username=cpf)
        except User.DoesNotExist:
            return cpf
        raise forms.ValidationError(self.error_messages['duplicate_username'])

    def clean_email(self):
        email = self.cleaned_data['email']
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            return email
        raise forms.ValidationError(self.error_messages['duplicate_email'])
    
    def clean_password2(self):
        password1 = self.cleaned_data.get("password1", "")
        password2 = self.cleaned_data["password2"]
        if password1 != password2:
            raise forms.ValidationError(
                self.error_messages['password_mismatch'])
        return password2

    def save(self, commit=True):
        usuario = super(forms.ModelForm, self).save(commit=False)
        usuario.set_password(self.cleaned_data["password1"])
        if commit:
            usuario.save()
        return usuario


class RegistroEnderecoForm(forms.ModelForm):
    class Meta:
        model = Endereco
        exclude = ('usuario',)


class RegistroTelefoneForm(forms.ModelForm):
    class Meta:
        model = Telefone
        exclude = ('usuario',)


class CustomUserChangeForm(UserChangeForm):
    invalid_cpf_msg = 'Esse campo deve conter um CPF válido com 11 números.'

    username = forms.RegexField(
        label='CPF', max_length=11, regex=r'^\d{11}$',
        help_text = 'Obrigatório. 11 caracteres. Apenas números.',
        error_messages = {'invalid': invalid_cpf_msg})
    email = forms.EmailField(label='Email', required=True, 
        help_text = 'Obrigatório.',
        error_messages = {
            'invalid': 'Esse campo deve conter um email válido.'})

    def clean_username(self):
        cpf = self.cleaned_data['username']
        if not validate_cpf(cpf):
            raise forms.ValidationError(self.invalid_cpf_msg)

        return cpf


class CustomUserCreationForm(UserCreationForm):
    invalid_cpf_msg = 'Esse campo deve conter um CPF válido com 11 números.'

    username = forms.RegexField(label='CPF', max_length=11, regex=r'^\d{11}$',
        help_text = 'Obrigatório. 11 caracteres. Apenas números.',
        error_messages = {'invalid': invalid_cpf_msg})
    email = forms.EmailField(label='Email', required=True, 
        help_text = 'Obrigatório.',
        error_messages = {
            'invalid': 'Esse campo deve conter um email válido.'})

    def clean_username(self):
        cpf = self.cleaned_data['username']
        if not validate_cpf(cpf):
            raise forms.ValidationError(self.invalid_cpf_msg)

        return cpf


class ItemPedidoForm(forms.ModelForm):
    item = forms.ModelChoiceField(queryset=Item.objects.all(), required=True, 
        initial=1)

    class Meta:
        model = ItemPedido
        exclude = ('pedido',)


class PizzaPedidaForm(forms.ModelForm):
    invalid_number_of_pizzas = (u'Você deve escolher 1, 2 ou 4 sabores '
        + 'diferentes de pizza.')
    
    tamanho = forms.ChoiceField(choices=PizzaPedida.TAMANHO_CHOICES, 
        required=True, initial='G')

    class Meta:
        model = PizzaPedida
        exclude = ('pedido',)
    
    def clean(self):
        cleaned_data = super(PizzaPedidaForm, self).clean()
        if len(self.cleaned_data['pizza']) in [1, 2, 4]:
            return cleaned_data
        else:
            raise forms.ValidationError(self.invalid_number_of_pizzas)


class ConfirmarPedidoForm(forms.ModelForm):
    error_messages = {
        'insufficient': (u'A quantia precisa ser no mínimo maior que R$%s.'),
    }

    endereco = forms.ModelChoiceField(queryset=Endereco.objects.all(), 
        widget=RadioSelect, empty_label=None)
    telefone = forms.ModelChoiceField(queryset=Telefone.objects.all(), 
        widget=RadioSelect, empty_label=None)

    class Meta:
        model = Pedido
        fields = ('endereco', 'telefone', 'valor_pago',)
    
    def clean_valor_pago(self):
        valor_pago = self.cleaned_data['valor_pago']
        valor_total = self.instance.valor_total(self.cleaned_data['endereco'])
        if valor_total <= valor_pago:
            return valor_pago
        else:
            raise forms.ValidationError(self
                .error_messages['insufficient'] % valor_total)
